package com.hustbaidu.hustmap;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Bitmap.Config;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.SimpleOnGestureListener;

public class MapBackgroundView extends View {
	public int realDistanceX, realDistanceY;
	public int placeOffsetX, placeOffsetY;
	
	private Bitmap bm;
	private Bitmap mapBackground;
	private int mapChipWidth, mapChipHeight;
	private int mapChipNumX, mapChipNumY;
	private int mapChipTotalX, mapChipTotalY;
	private int mapViewWidth, mapViewHeight;
	private int currentChipX, currentChipY;
	private int offsetX, offsetY;
	private int oldOffsetX, oldOffsetY;
	
	private GestureDetector myGestureDetector;
	private String chipImgPath;
	private String[][] mapChipName;
	private HustMapView hustMapView;

	public MapBackgroundView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
	}

	public MapBackgroundView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	public MapBackgroundView(Context context, HustMapView hustMapView) {
		super(context);
		// TODO Auto-generated constructor stub
		this.hustMapView = hustMapView;
				
		offsetX = 0;
		offsetY = 0;
		oldOffsetX = 0;
		oldOffsetY = 0;
		currentChipX = 0;
		currentChipY = 0;
		
		realDistanceX = 0;
		realDistanceY = 0;
		
		myGestureDetector = new GestureDetector(new MyGestureListener());
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
//		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
		mapViewWidth = widthMeasureSpec;
		mapViewHeight = heightMeasureSpec;
		updateMapBackground(true, 0);
//		System.out.println(mapViewWidth + " : " + mapViewHeight);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
//		return super.onTouchEvent(event);
		myGestureDetector.onTouchEvent(event);
		return true;
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
				
		Rect src = new Rect(offsetX, offsetY, offsetX + mapViewWidth, offsetY + mapViewHeight);
		Rect dst = new Rect(0, 0, mapViewWidth, mapViewHeight);
		canvas.drawBitmap(mapBackground, src, dst, null);
//		System.out.println("onDraw");
	}
	
	private void updateMapBackground(boolean flag, int d){
		if(flag){
			mapChipNumX = mapViewWidth / mapChipWidth + 2;
			if(mapChipNumX > mapChipTotalX){
				mapChipNumX = mapChipTotalX;
			}
			mapChipNumY = mapViewHeight / mapChipHeight + 2;
			if(mapChipNumY > mapChipTotalY){
				mapChipNumY = mapChipTotalY;
			}
			
			mapBackground = Bitmap.createBitmap(mapChipWidth * mapChipNumX, mapChipHeight * mapChipNumY, Config.ARGB_8888);
			Canvas cv = new Canvas(mapBackground);
			for(int i = 0; i < mapChipNumX; i++){
				for(int j = 0; j < mapChipNumY; j++){
//					System.out.println((currentChipX + i) + " : " + (currentChipY + j));
//					System.out.println(chipImgPath + "/" + mapChipName[currentChipX + i][currentChipY + j]);
					bm = getLoacalBitmap(chipImgPath + "/" + mapChipName[currentChipX + i][currentChipY + j]);
					cv.drawBitmap(bm, mapChipWidth * i, mapChipHeight * j, null);
				}
			}

		}
		
		else{
			Bitmap bmBuffer = Bitmap.createBitmap(mapChipWidth * mapChipNumX, mapChipHeight * mapChipNumY, Config.ARGB_8888);
			Canvas cv = new Canvas(bmBuffer);
//			cv.drawRGB(255, 255, 255);
//			Canvas cv = new Canvas(mapBackground);
			Rect src;
			Rect dst;
			switch(d){
				case 1 : 
//					System.out.println("case 1");
					src = new Rect(mapChipWidth, 0, mapChipWidth * mapChipNumX, mapChipHeight * mapChipNumY);
					dst = new Rect(0, 0, mapChipWidth * (mapChipNumX - 1), mapChipHeight * mapChipNumY);
					cv.drawBitmap(mapBackground, src, dst, null);
					for(int i = 0; i < mapChipNumY; i++){
						bm = getLoacalBitmap(chipImgPath + "/" + mapChipName[currentChipX + mapChipNumX - 1][currentChipY + i]);
						cv.drawBitmap(bm, mapChipWidth * (mapChipNumX - 1), mapChipHeight * i, null);
					}
					break;
					
				case 2 :
//					System.out.println("case 2");
					src = new Rect(0, mapChipHeight, mapChipWidth * mapChipNumX, mapChipHeight * mapChipNumY);
					dst = new Rect(0, 0, mapChipWidth * mapChipNumX, mapChipHeight * (mapChipNumY - 1));
					cv.drawBitmap(mapBackground, src, dst, null);
					for(int i = 0; i < mapChipNumX; i++){
						bm = getLoacalBitmap(chipImgPath + "/" + mapChipName[currentChipX + i][currentChipY + mapChipNumY - 1]);
						cv.drawBitmap(bm, mapChipWidth * i, mapChipHeight * (mapChipNumY - 1), null);
					}
					break;
					
				case 3 :
//					System.out.println("case 3");
					src = new Rect(0, 0, mapChipWidth * (mapChipNumX - 1), mapChipHeight * mapChipNumY);
					dst = new Rect(mapChipWidth, 0, mapChipWidth * mapChipNumX, mapChipHeight * mapChipNumY);
					cv.drawBitmap(mapBackground, src, dst, null);
					for(int i = 0; i < mapChipNumY; i++){
						bm = getLoacalBitmap(chipImgPath + "/" + mapChipName[currentChipX][currentChipY + i]);
						cv.drawBitmap(bm, 0, mapChipHeight * i, null);
					}
					break;
					
				case 4 :
//					System.out.println("case 4");
					src = new Rect(0, 0, mapChipWidth * mapChipNumX, mapChipHeight * (mapChipNumY - 1));
					dst = new Rect(0, mapChipHeight, mapChipWidth * mapChipNumX, mapChipHeight * mapChipNumY);
					cv.drawBitmap(mapBackground, src, dst, null);
					for(int i = 0; i < mapChipNumX; i++){
						bm = getLoacalBitmap(chipImgPath + "/" + mapChipName[currentChipX + i][currentChipY]);
						cv.drawBitmap(bm, mapChipWidth * i, 0, null);
					}
					break;
			}
//			LoadBitmapThread loadBitmapThread = new LoadBitmapThread(d);
//			loadBitmapThread.start();
			cv = new Canvas(mapBackground);
			cv.drawBitmap(bmBuffer, new Rect(0, 0, mapChipWidth * mapChipNumX, mapChipHeight * mapChipNumY), new Rect(0, 0, mapChipWidth * mapChipNumX, mapChipHeight * mapChipNumY), null);
		}

	}
	
	private class LoadBitmapThread extends Thread{
		private int flag;
		
		public LoadBitmapThread(int flag) {
			super();
			// TODO Auto-generated constructor stub
			this.flag = flag;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			Canvas cv = new Canvas(mapBackground);
			switch (flag) {
			case 1:
				for(int i = 0; i < mapChipNumY; i++){
					bm = getLoacalBitmap(chipImgPath + "/" + mapChipName[currentChipX + mapChipNumX - 1][currentChipY + i]);
					cv.drawBitmap(bm, mapChipWidth * (mapChipNumX - 1), mapChipHeight * i, null);
				}
				break;
				
			case 2:
				for(int i = 0; i < mapChipNumX; i++){
					bm = getLoacalBitmap(chipImgPath + "/" + mapChipName[currentChipX + i][currentChipY + mapChipNumY - 1]);
					cv.drawBitmap(bm, mapChipWidth * i, mapChipHeight * (mapChipNumY - 1), null);
				}
				break;
				
			case 3:
				for(int i = 0; i < mapChipNumY; i++){
					bm = getLoacalBitmap(chipImgPath + "/" + mapChipName[currentChipX][currentChipY + i]);
					cv.drawBitmap(bm, 0, mapChipHeight * i, null);
				}
				break;
				
			case 4:
				for(int i = 0; i < mapChipNumX; i++){
					bm = getLoacalBitmap(chipImgPath + "/" + mapChipName[currentChipX + i][currentChipY]);
					cv.drawBitmap(bm, mapChipWidth * i, 0, null);
				}
				break;

			default:
				break;
			}
		}
		
	}
	
	private static Bitmap getLoacalBitmap(String url) {
        try {
             FileInputStream fis = new FileInputStream(url);
             return BitmapFactory.decodeStream(fis);  ///把流转化为Bitmap图片         

          } catch (FileNotFoundException e) {
             e.printStackTrace();
             return null;
        }
   }

	public void initMapChip(String imgPrefix){
		mapChipName = new String[mapChipTotalX][mapChipTotalY];
		
		for(int i = 0; i < mapChipTotalY; i++){
			for(int j = 0; j < mapChipTotalX; j++){
				mapChipName[j][i] = imgPrefix + String.valueOf(i + 1) + "_" + String.valueOf(j + 1) + ".png"; 
			}
		}
	}
	
	private void moveAdjust(){
		if(offsetX < 0){
			if(currentChipX > 0){
				currentChipX--;
				updateMapBackground(false, 3);
				realDistanceX = offsetX - oldOffsetX;
				offsetX += mapChipWidth;
			}
			else{
				offsetX = 0;
				realDistanceX = offsetX - oldOffsetX;
			}
		}
		
		if(offsetY < 0){
			if(currentChipY > 0){
				currentChipY--;
				updateMapBackground(false, 4);
				realDistanceY = offsetY - oldOffsetY;
				offsetY += mapChipHeight;
			}
			else{
				offsetY = 0;
				realDistanceY = offsetY - oldOffsetY;
				
			}
		}

		if(offsetX + mapViewWidth > mapChipWidth * mapChipNumX){
			if(currentChipX + mapChipNumX < mapChipTotalX){
				currentChipX++;
				updateMapBackground(false, 1);
				realDistanceX = offsetX - oldOffsetX;
				offsetX -= mapChipWidth;
			}
			else{
				offsetX = mapChipWidth * mapChipNumX - mapViewWidth;
				realDistanceX = offsetX - oldOffsetX;
			}
		}
		
		if(offsetY + mapViewHeight > mapChipHeight * mapChipNumY){
			if(currentChipY + mapChipNumY < mapChipTotalY){
				currentChipY++;
				updateMapBackground(false, 2);
				realDistanceY = offsetY - oldOffsetY;
				offsetY -= mapChipHeight;
			}
			else{
				offsetY = mapChipHeight * mapChipNumY - mapViewHeight;
				realDistanceY = offsetY - oldOffsetY;
			}
		}
				
		oldOffsetX = offsetX;
		oldOffsetY = offsetY;
	}
	
	public void choosePlace(PlaceInfo place){
		
		if(place != null){
			jumpTo(place.getPlacePositionX(), place.getPlacePositionY());
		}
	}
	
	private void jumpTo(int destinationX, int destinationY){
		if((destinationX - 0) < (mapViewWidth / 2)){
			offsetX = 0;
			currentChipX = 0;
			placeOffsetX = destinationX;
		}
		else if((mapChipWidth * mapChipTotalX - destinationX) < (mapViewWidth / 2)){
			offsetX = mapChipWidth * mapChipNumX - mapViewWidth;
			currentChipX = mapChipTotalX - mapChipNumX;
			placeOffsetX = mapViewWidth - (mapChipWidth * mapChipTotalX - destinationX);
		}
		else{
			int destinationChipX = destinationX / mapChipWidth;
			int destinationOffsetXInChip = destinationX % mapChipWidth;
			
			int leftChipNum = ((mapViewWidth / 2) - destinationOffsetXInChip) / mapChipWidth + 1;
			
			int tmpChipX = destinationChipX - leftChipNum;
			if(tmpChipX + mapChipNumX - 1 >= mapChipTotalX){
				currentChipX = mapChipTotalX - mapChipNumX;	
			}
			else{
				currentChipX = tmpChipX;
			}
			offsetX = (destinationChipX - currentChipX) * mapChipWidth + destinationOffsetXInChip - (mapViewWidth / 2);
			placeOffsetX = mapViewWidth / 2;
		}
		
		if((destinationY - 0) < (mapViewHeight / 2)){
			offsetY = 0;
			currentChipY = 0;
			placeOffsetY = destinationY;
		}
		else if((mapChipHeight * mapChipTotalY - destinationY) < (mapViewHeight / 2)){
			offsetY = mapChipHeight * mapChipNumY - mapViewHeight;
			currentChipY = mapChipTotalY - mapChipNumY;
			placeOffsetY = mapViewHeight - (mapChipHeight * mapChipTotalY - destinationY);
		}
		else{
			int destinationChipY = destinationY / mapChipHeight;
			int destinationOffsetYInChip = destinationY % mapChipHeight;
			
			int topChipNum = ((mapChipHeight / 2) - destinationOffsetYInChip) / mapChipHeight + 1;
			
			int tmpChipY = destinationChipY - topChipNum;
			if(tmpChipY + mapChipNumY - 1 >= mapChipTotalY){
				currentChipY = mapChipTotalY - mapChipNumY;	
			}
			else{
				currentChipY = tmpChipY;
			}
			offsetY = (destinationChipY - currentChipY) * mapChipHeight + destinationOffsetYInChip - (mapViewHeight / 2);
			placeOffsetY = mapViewHeight / 2;
		}
		
		updateMapBackground(true, 0);
		
	}
	
	public int[] relativeToAbsolute(int x, int y){
		int[] position = new int[2];
		position[0] = currentChipX * mapChipWidth + offsetX + x;
		position[1] = currentChipY * mapChipHeight + offsetY + y;
		return position;
	}
	
	public void moveBy(int distanceX, int distanceY){
		realDistanceX = distanceX;
		realDistanceY = distanceY;
		offsetX = offsetX + distanceX;
		offsetY = offsetY + distanceY;
		moveAdjust();
//		System.out.println(offsetX + " : " + offsetY);
	}
	
	
	
	public int getOffsetX() {
		return offsetX;
	}

	public int getOffsetY() {
		return offsetY;
	}
	
	public void setMapChipWidth(int mapChipWidth) {
		this.mapChipWidth = mapChipWidth;
	}

	public int getMapChipWidth() {
		return mapChipWidth;
	}
	
	public void setMapChipHeight(int mapChipHeight) {
		this.mapChipHeight = mapChipHeight;
	}
	
	public int getMapChipHeight() {
		return mapChipHeight;
	}

	public void setMapChipTotalX(int mapChipTotalX) {
		this.mapChipTotalX = mapChipTotalX;
//		System.out.println("totalX : " + this.mapChipTotalX);
	}

	public void setMapChipTotalY(int mapChipTotalY) {
		this.mapChipTotalY = mapChipTotalY;
//		System.out.println("totalY : " + this.mapChipTotalY);
	}

	public int getCurrentChipX() {
		return currentChipX;
	}

	public int getCurrentChipY() {
		return currentChipY;
	}
	
	public void setChipImgPath(String chipImgPath) {
		this.chipImgPath = chipImgPath;
	}






	private class MyGestureListener extends SimpleOnGestureListener{
		
		@Override
		public boolean onSingleTapConfirmed(MotionEvent e) {
			// TODO Auto-generated method stub
//			System.out.println("onSingleTapConfirmed");
//			System.out.println("2 -- " + e.getX() + " : " + e.getY());
//			int realOffsetX = currentChipX * mapChipWidth + offsetX + (int)e.getX();
//			int realOffsetY = currentChipY * mapChipHeight + offsetY + (int)e.getY();
			int[] realOffset = new int[2];
			realOffset = relativeToAbsolute((int)e.getX(), (int)e.getY());
			System.out.println("touch point : " + realOffset[0] + " : " + realOffset[1]);
			hustMapView.touchOnPlace(realOffset[0], realOffset[1]);
			
			return super.onSingleTapConfirmed(e);
		}

		@Override
		public boolean onSingleTapUp(MotionEvent e) {
			// TODO Auto-generated method stub
//			System.out.println("onSingleTapUp");
			return super.onSingleTapUp(e);
		}

		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2,
				float distanceX, float distanceY) {
			// TODO Auto-generated method stub
			return super.onScroll(e1, e2, distanceX, distanceY);
		}
		
		@Override
		public void onLongPress(MotionEvent e) {
			// TODO Auto-generated method stub
//			showContextMenu();
			super.onLongPress(e);
		}
		
	}

}
